package com.myk.game.gobangchess.rooms;

import com.myk.game.gobangchess.*;
import com.myk.game.gobangchess.ai.shock.P4_Engine;
import com.myk.game.gobangchess.constants.BoardStyleData;
import com.myk.game.gobangchess.constants.ColorCost;
import com.myk.game.gobangchess.constants.WinMode;
import com.myk.game.gobangchess.rooms.absrooms.AbsAiRoom;
import com.myk.game.gobangchess.signs.AroundSign;
import com.myk.game.gobangchess.signs.BadgeSign;
import com.myk.game.gobangchess.signs.LineSign;
import com.myk.game.gobangchess.utils.GridsUtils;

import java.util.*;

/**
 * 震棋AI房间
 */
public class ShockAiRoom extends AbsAiRoom {

    private int[] lastPoint;

    private List<int[]> thePrePoint = new ArrayList<>();
    private List<int[]> theNowPoint = new ArrayList<>();

    public ShockAiRoom(String roomName) {
        super(roomName, "震棋，和逆界千分大佬obli写的ai对战。", "震棋AI版", BoardStyleData.getGoBangStyle(8, 8), false, false);
    }

    @Override
    public String getRuleText() {
        return "玩家上桌后ai机器人会自动成为对手，玩家离开ai机器人也会自动离开。\n" +
                "双方轮流落子，落子后会击退周围一圈所有棋子1格，如果击退到的格子已经有棋子了则不能击退，可将棋子击退出棋盘外移除掉。  落子后或者击退棋子后棋子形成四连立刻获胜。";
    }

    @Override
    public void resetGrids() {
        super.resetGrids();
        lastPoint = null;
        thePrePoint = new ArrayList<>();
        theNowPoint = new ArrayList<>();
    }

    @Override
    public void doRule(int row, int col, int value) {
        if (curGrids[row][col] == 0) { //只能落在空位置
            stepAdd();
            curGrids[row][col] = value; //实际落子
            lastPoint = new int[]{row, col, value};
            ShockAiRoom.WinState winState = checkWin();
            if (winState != null) {
                doOver(winState.winMode, winState.winMsg);
            }
            else {
                ShockPiece();
                ShockAiRoom.WinState winState2 = checkWin();
                if (winState2 != null) {
                    doOver(winState2.winMode, winState2.winMsg);
                }
                else {
                    addHistory();
                    noticeChangeMove();
                }
            }
        }
    }

    // 创建陪玩的ai机器人
    @Override
    protected RobotPlayer createRobotPlayer() {
        String[] names = {"#震侠", "#震王"};
        String name;
        int level;
        int rdm = (int) (Math.random() * 4);
        if (rdm < 3){
            name = names[0];
            level = 1;
        }
        else {
            name = names[1];
            level = 2;
        }
        return new RobotPlayer(this, "obli1234zqai", name, () -> {
            int[][] board = GridsUtils.copyGrids(curGrids);
            for (int i = 0; i < board.length; i++) {
                for (int j = 0; j < board[0].length; j++) {
                    if (board[i][j] == 2) {
                        board[i][j] = -1; //逆界中白棋子是2，ai中白棋子是-1
                    }
                }
            }
            int playerTurn = 1;  //当前行动方  1：黑方    2：白方
            if (cur == 2) {
                playerTurn = -1;
            }

            /*System.out.println("ai落子前");
            print(board);*/

            int difficulty = level; //难度 1-2级

            //System.out.println("playerTurn：" + playerTurn);

            int[] point = P4_Engine.p4_engine(board, playerTurn, difficulty);

            //System.out.println("震棋ai落点 point: " + point[0] + "," + point[1]);

            Player player = playerTurn == 1 ? player_black : player_white;
            int row = point[0] - 1;
            int col = point[1] - 1;

            try {
                Thread.sleep(500);
            }
            catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            moveLater(player, row, col);

            /*System.out.println("代码落子后");
            int[][] board2 = GridsUtils.copyGrids(curGrids);
            print(board2);*/
        });
    }

    private static void print(int[][] array) {
        for (int i = 0; i < array.length; i++) {
            for (int j = 0; j < array[0].length; j++) {
                System.out.print(array[i][j] + " ");
            }
            System.out.println();
        }
        System.out.println();
    }

    private void ShockPiece() {
        /*
        int[][] moves = {
                {-1, -1}, {-1, 0}, {-1, 1},
                { 0, -1},          { 0, 1},
                { 1, -1}, { 1, 0}, { 1, 1}
        };
         */
        int[][] moves = {
                {-1, -1}, {-1, 0}, {-1, 1},
                {0, -1}, {0, 1},
                {1, -1}, {1, 0}, {1, 1}
        };
        for (int[] move : moves) {
            int nextRow = lastPoint[0] + move[0];
            int nextCol = lastPoint[1] + move[1];
            if (nextRow < curGrids.length && nextCol < curGrids[0].length && nextRow >= 0 && nextCol >= 0) {
                if (curGrids[nextRow][nextCol] != 0) {
                    int value = curGrids[nextRow][nextCol];
                    int moreNextRow = nextRow + move[0];
                    int moreNextCol = nextCol + move[1];
                    if (moreNextRow < 0 || moreNextRow >= curGrids.length || moreNextCol < 0 || moreNextCol >= curGrids[0].length) {
                        curGrids[nextRow][nextCol] = 0;
                        thePrePoint.add(new int[]{nextRow, nextCol});
                        theNowPoint.add(new int[]{moreNextRow, moreNextCol, value});
                    }
                    else if (curGrids[moreNextRow][moreNextCol] == 0) {
                        curGrids[moreNextRow][moreNextCol] = value;
                        curGrids[nextRow][nextCol] = 0;
                        thePrePoint.add(new int[]{nextRow, nextCol});
                        theNowPoint.add(new int[]{moreNextRow, moreNextCol});
                    }
                }
            }
        }
    }

    @Override
    public String getGameInfo() {
        signList.clear();
        if (lastPoint != null) {
            signList.add(new AroundSign(getIndex(lastPoint[0], lastPoint[1]), "#00000000", "#FF00FF00", 1.0f));
        }
        if (!thePrePoint.isEmpty()) {
            int size = thePrePoint.size();
            for (int i = 0; i < size; i++) {
                int[] prePoint = thePrePoint.get(i);
                int[] nowPoint = theNowPoint.get(i);
                if (nowPoint[0] < 0 || nowPoint[0] >= curGrids.length || nowPoint[1] < 0 || nowPoint[1] >= curGrids[0].length) {
                    addArrowSignalShort(prePoint[0], prePoint[1], nowPoint[0], nowPoint[1], nowPoint[2]);
                }
                else {
                    addArrowSignal(prePoint[0], prePoint[1], nowPoint[0], nowPoint[1]);
                }
            }
        }
        return super.getGameInfo();
    }

    public void addArrowSignal(int startRow, int startCol, int endRow, int endCol) {
        signList.add(new LineSign(getIndex(startRow, startCol), getIndex(endRow, endCol), ColorCost.MOVE_ARROW, 1));
    }

    public void addArrowSignalShort(int startRow, int startCol, int endRow, int endCol, int endValue) {
        if (startRow > endRow && startCol > endCol) {
            signList.add(new BadgeSign(getIndex(startRow, startCol), "↖", 0, ColorCost.MOVE_ARROW, endValue == 2 ? ColorCost.DETAINED_BADGE_BLACK : ColorCost.DETAINED_BADGE_WHITE));
        }
        else if (startRow > endRow && startCol < endCol) {
            signList.add(new BadgeSign(getIndex(startRow, startCol), "↗", 2, ColorCost.MOVE_ARROW, endValue == 2 ? ColorCost.DETAINED_BADGE_BLACK : ColorCost.DETAINED_BADGE_WHITE));
        }
        else if (startRow < endRow && startCol > endCol) {
            signList.add(new BadgeSign(getIndex(startRow, startCol), "↙", 6, ColorCost.MOVE_ARROW, endValue == 2 ? ColorCost.DETAINED_BADGE_BLACK : ColorCost.DETAINED_BADGE_WHITE));
        }
        else if (startRow < endRow && startCol < endCol) {
            signList.add(new BadgeSign(getIndex(startRow, startCol), "↘", 8, ColorCost.MOVE_ARROW, endValue == 2 ? ColorCost.DETAINED_BADGE_BLACK : ColorCost.DETAINED_BADGE_WHITE));
        }
        else if (startRow == endRow && startCol > endCol) {
            signList.add(new BadgeSign(getIndex(startRow, startCol), "←", 3, ColorCost.MOVE_ARROW, endValue == 2 ? ColorCost.DETAINED_BADGE_BLACK : ColorCost.DETAINED_BADGE_WHITE));
        }
        else if (startRow == endRow && startCol < endCol) {
            signList.add(new BadgeSign(getIndex(startRow, startCol), "→", 5, ColorCost.MOVE_ARROW, endValue == 2 ? ColorCost.DETAINED_BADGE_BLACK : ColorCost.DETAINED_BADGE_WHITE));
        }
        else if (startRow > endRow) {
            signList.add(new BadgeSign(getIndex(startRow, startCol), "↑", 1, ColorCost.MOVE_ARROW, endValue == 2 ? ColorCost.DETAINED_BADGE_BLACK : ColorCost.DETAINED_BADGE_WHITE));
        }
        else if (startRow < endRow) {
            signList.add(new BadgeSign(getIndex(startRow, startCol), "↓", 7, ColorCost.MOVE_ARROW, endValue == 2 ? ColorCost.DETAINED_BADGE_BLACK : ColorCost.DETAINED_BADGE_WHITE));
        }
    }

    private void noticeChangeMove() {
        if (cur == 1) {
            noticeWhiteMove();
        }
        else if (cur == 2) {
            noticeBlackMove();
        }
        thePrePoint = new ArrayList<>();
        theNowPoint = new ArrayList<>();
    }

    //获取成5的次数
    protected ShockAiRoom.WinState checkWin() {
        int lengthB = checkFormation(1, 4);
        int lengthW = checkFormation(2, 4);
        boolean isBW = lengthB > 0;
        boolean isWW = lengthW > 0;
        boolean gridFull = GridsUtils.getDataCount(curGrids, 0) == 0;
        int winValue = 0;
        if (cur == 1 ? isBW : isWW) {
            winValue = cur;
        }
        else if (cur == 1 ? isWW : isBW) {
            winValue = cur == 1 ? 2 : 1;
        }
        if (winValue == 1) {
            return new ShockAiRoom.WinState(WinMode.BLACK_WIN, player_black.getNickNameOrTemp() + "执黑棋战胜" + player_white.getNickNameOrTemp());
        }
        else if (winValue == 2) {
            return new ShockAiRoom.WinState(WinMode.WHITE_WIN, player_white.getNickNameOrTemp() + "执白棋战胜" + player_black.getNickNameOrTemp());
        }
        else if (gridFull) {
            return new ShockAiRoom.WinState(WinMode.BOTH_DRAW, player_black.getNickNameOrTemp() + "-黑棋战平" + player_white.getNickNameOrTemp() + "-白棋");
        }
        else {
            return null;
        }
    }


    private int checkFormation(int value, int winLength) {
        int rows = curGrids.length;
        int cols = curGrids[0].length;
        int formationCount = 0;

        // 水平方向
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols - winLength + 1; j++) {
                int length = 0;
                for (int k = j; k < j + winLength; k++) {
                    if (curGrids[i][k] == value) {
                        length++;
                    }
                    else {
                        break;
                    }
                }
                if (length >= winLength) {
                    formationCount += (length - winLength + 1);
                }
            }
        }

        // 垂直方向
        for (int i = 0; i < rows - winLength + 1; i++) {
            for (int j = 0; j < cols; j++) {
                int length = 0;
                for (int k = i; k < i + winLength; k++) {
                    if (curGrids[k][j] == value) {
                        length++;
                    }
                    else {
                        break;
                    }
                }
                if (length >= winLength) {
                    formationCount += (length - winLength + 1);
                }
            }
        }

        // 左上到右下方向
        for (int i = 0; i < rows - winLength + 1; i++) {
            for (int j = 0; j < cols - winLength + 1; j++) {
                int length = 0;
                for (int k = 0; k < winLength; k++) {
                    if (curGrids[i + k][j + k] == value) {
                        length++;
                    }
                    else {
                        break;
                    }
                }
                if (length >= winLength) {
                    formationCount += (length - winLength + 1);
                }
            }
        }

        // 右上到左下方向
        for (int i = 0; i < rows - winLength + 1; i++) {
            for (int j = winLength - 1; j < cols; j++) {
                int length = 0;
                for (int k = 0; k < winLength; k++) {
                    if (curGrids[i + k][j - k] == value) {
                        length++;
                    }
                    else {
                        break;
                    }
                }
                if (length >= winLength) {
                    formationCount += (length - winLength + 1);
                }
            }
        }

        return formationCount;
    }


    // 判断位置在棋盘上
    protected boolean isInGrids(int row, int col) {
        return row >= 0 && row <= curGrids.length - 1 && col >= 0 && col <= curGrids[0].length - 1;
    }

    protected int getJudgeLength(int x, int y, int dx, int dy) {
        int value = curGrids[x][y];
        int length = 0;
        while (isInGrids(x, y)) {
            if (curGrids[x][y] != value) {
                return length;
            }
            length++;
            x += dx;
            y += dy;
        }
        return length;
    }

    public static class WinState {
        public int winMode;
        public String winMsg;

        public WinState(int winMode, String winMsg) {
            this.winMode = winMode;
            this.winMsg = winMsg;
        }

    }

}
